//  ---------------------------------------------------------------------------
//  Department of Computer Science, University of Hull
//  DirectX 11 framework, Aug 2012
//
//  ---------------------------------------------------------------------------

#pragma once
#include <d3d11.h>
#include <d3dx11Effect.h>
#include <dxerr.h>
#include <xnamath.h>
#include <cassert>
#include <vector>
#include <AntTweakBar.h>

class DxApp {
private:
	static DxApp* _instance;
	HINSTANCE _hApp;
	HWND _hWnd;

protected:
	ID3D11Device *_dxDev;
	ID3D11DeviceContext *_dxImmedDC;
	IDXGISwapChain *_swapChain;
	DXGI_SWAP_CHAIN_DESC _swapChainDesc;
	
	ID3D11RenderTargetView *_renderTargetView;
	ID3D11DepthStencilView *_depthStencilView;
	D3D11_TEXTURE2D_DESC _depthStencilDesc;

	bool	m_DX11;

private:
	static LRESULT CALLBACK MessageProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam);
	
	HRESULT initialiseDxDevice();
	HRESULT createDepthStencilView();
	HRESULT createRenderTargetView();
	void setupViewport();

	int		_width;
	int		_height;

protected:
	bool loadEffects(const char* filename, std::vector<char> &compiledShader);
	
public:
	DxApp();
	virtual ~DxApp();

	int width() { return _width; }
	int height() { return _height; }
	virtual bool initialise(HINSTANCE instance, int cmdShow, int w=600, int h=600);
	int run();

	virtual void renderScene() = 0;
	virtual void updateScene() = 0;

	virtual void onLButtonDown() = 0;
	virtual void onLButtonUp() = 0;
	virtual void onMouseMove(LPARAM lparam) = 0;

	virtual void onKey(WPARAM wParam) = 0;

	virtual HRESULT onResize(int width, int height);

	bool dx11Support() { return m_DX11; }

	// Effect Variables Setters
	// __ Matrices
	bool setMatrixVar(ID3DX11Effect* fx, const void*       mtx, const char* var_name);
	// __Vectors
	bool setVectorVar(ID3DX11Effect* fx, const void* data,    const char* var_name);
	// __Srv
	bool setSrvVar(ID3DX11Effect* fx, ID3D11ShaderResourceView* srv, const char* var_name);
	bool setSrvArrayVar(ID3DX11Effect* fx, ID3D11ShaderResourceView** srv, const char* var_name, unsigned int offset, unsigned int count);
	// __Scalars
	bool setFloatVar(ID3DX11Effect* fx, float data, const char* var_name);
	bool setIntVar(ID3DX11Effect* fx, int data, const char* var_name);
	bool setBoolVar(ID3DX11Effect* fx, bool data, const char* var_name);

	static HINSTANCE hApp() { assert(_instance); return _instance->_hApp; }
	static HWND hWnd() { assert(_instance); return _instance->_hWnd; }
};

// Debug trace macro for DirectX
#ifdef _DEBUG
	#ifndef HR
		#define DXCHECK(x)										\
		{														\
			HRESULT hr = (x);									\
			if (FAILED(hr)) {									\
				DXTrace(__FILE__,__LINE__, hr, L#x, true);		\
			}													\
		}
	#endif
#else
	#ifndef HR
		#define DXCHECK(x) (x)
	#endif
#endif

// Debug trace macro for DirectX
#ifdef _DEBUG
	#ifndef HRRETURN
		#define DXRETURN(x)										\
		{														\
			HRESULT hr = (x);									\
			if (FAILED(hr)) {									\
				DXTrace(__FILE__,__LINE__, hr, L#x, true);		\
				return hr;										\
			}													\
		}
	#endif
#else
	#ifndef HR
		#define DXRETURN(x)										\
		{														\
			HRESULT hr = (x);									\
			if (FAILED(hr)) {									\
				return hr;										\
			}													\
		}
	#endif
#endif